import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import jocode.*;
import processing.opengl.*;

// handles for textures
int sphereTextureHandle = 0;
int sphereTextureHandleD = 0;
int groundTextureHandle = 0;
int houseTextureHandle = 0;
// display list for skydome
int skydomeDL = 0;
// light position: 
//  if last value is 0, then this describes light direction
//  if 1, then light position
float lightPosition[]= { -2f, 2f, 2f, 0f };
// a camera and a cam to move around scene
JOCamera camera1 = new JOCamera();
JOCam cam = new JOCam(camera1);
// SPACE key toggles dusk/daylight
boolean dusk = false;

void setup() {
  size(800, 600, OPENGL);
  JOBridgeP5.init(this);
  
  // create textures
  sphereTextureHandle = JOApp.makeTexture("dayfair_skydome_1.jpg");
  sphereTextureHandleD = JOApp.makeTexture("dayfair_skydome_1_dusk.jpg");
  groundTextureHandle = JOApp.makeTexture("grass_1_512.jpg", true, true);
  houseTextureHandle = JOApp.makeTexture("house_Stirling_House_t.png");

  // set camera 1 position
  camera1.setCamera(0, 25, 130,   // position of camera 
  		    -.1f, 0, -1,  // direction camera is pointing NOT TARGET POSITION (different from gluLookAt()!)
  		    0, 1, 0);     // UP direction of camera
  
  // a little haze
  JOApp.setFog(new float[] {.5f,.5f,.5f,1f}, .001f);
  
  // make the skydome display list
  makeSkyDome();
}

public void makeSkyDome() {
  GLUquadric s = JOApp.glu.gluNewQuadric();
  JOApp.glu.gluQuadricOrientation(s, GLU.GLU_INSIDE);  // normals point inwards
  JOApp.glu.gluQuadricTexture(s, true);
  skydomeDL = JOApp.beginDisplayList();
  {
    JOApp.gl.glDisable(GL.GL_LIGHTING);
    JOApp.gl.glDisable(GL.GL_DEPTH_TEST);
    JOApp.gl.glColor4f(.62f, .62f, .626f, 1);
    JOApp.gl.glPushMatrix();
    {
      JOApp.gl.glRotatef(90f, 1, 0, 0);   // rotate the sphere to align the axis vertically
      JOApp.gl.glScalef(200, 200, 200);
      JOApp.glu.gluSphere(s, 1, 48, 48);  // run GL commands to draw sphere
    }
    JOApp.gl.glPopMatrix();
    JOApp.gl.glEnable(GL.GL_LIGHTING);
    JOApp.gl.glEnable(GL.GL_DEPTH_TEST);
  }
  JOApp.endDisplayList();
}

/**
 * move the skydome so it is always centered at the camera position
 * switch dome textures between day and dusk
 */
public void renderDome() {
  JOApp.gl.glPushMatrix();
  {
    JOApp.gl.glTranslatef(camera1.position.x, camera1.position.y, camera1.position.z);
    JOApp.gl.glBindTexture(GL.GL_TEXTURE_2D, dusk? sphereTextureHandleD : sphereTextureHandle);
    JOApp.callDisplayList(skydomeDL);
  }
  JOApp.gl.glPopMatrix();
}

public void renderHouse() {
  // draw the house on a plane
  JOApp.gl.glPushMatrix();
  {
    JOApp.gl.glTranslatef(0f, 70f, 0f);
    JOApp.gl.glBindTexture(GL.GL_TEXTURE_2D, houseTextureHandle);
    JOApp.renderPlane(150, 150, 10, 10);
  }
  JOApp.gl.glPopMatrix();
}

public void renderGround() {
  // draw the ground plane
  JOApp.gl.glPushMatrix();
  {
    JOApp.gl.glRotatef(-90, 1, 0, 0);
    JOApp.gl.glBindTexture(GL.GL_TEXTURE_2D, groundTextureHandle);
    JOApp.renderPlane(1000, 1000, 100, 100, 40, 40);
  }
  JOApp.gl.glPopMatrix();
}

/**
 * set the field of view and view depth
 */
public void setPerspective() {
  JOApp.setPerspective(50f, .1f, 5000f);
}

void draw() {
  // setup and enable perspective
  setPerspective();

  // Create a light (diffuse light, ambient light, position)
  JOApp.setLight(GL.GL_LIGHT1,
           new float[] { .51f, .51f, .51f, 1f },
           new float[] { .5f, .5f, .53f, 1f },
           new float[] { .1f, .1f, .1f, 1f },
  	   lightPosition);

  // bright light overall
  if (dusk) {
    JOApp.setAmbientLight(new float[] {.1f, .1f, .1f, 1});
  } else {
    JOApp.setAmbientLight(new float[] {1f, 1f, 1f, 1});
  }
  
  // medium bright material
  JOApp.setMaterial(new float[] {.8f, .8f, .8f, 1}, .5f);
  
  // enable lighting and texture rendering
  JOApp.gl.glEnable(GL.GL_LIGHTING);
  JOApp.gl.glEnable(GL.GL_TEXTURE_2D);

  // enable alpha transparency (so text will have transparent background)
  JOApp.gl.glEnable(GL.GL_BLEND);
  JOApp.gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);

  // user keystrokes adjust camera position    	
  cam.handleNavKeys(1f / frameRate);

  // clear depth buffer and color
  JOApp.gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

  // select model view for subsequent transforms
  JOApp.gl.glMatrixMode(GL.GL_MODELVIEW);
  JOApp.gl.glLoadIdentity();

  // do gluLookAt() with camera position, direction, orientation
  cam.render();

  // draw the sky
  renderDome();
  
  // draw the ground plane
  JOApp.gl.glPushMatrix();
  {
    JOApp.gl.glTranslatef(0f, -3f, 0f); // down a bit
    renderGround();
  }
  JOApp.gl.glPopMatrix();
  
  // draw house
  JOApp.gl.glPushMatrix();
  {
    JOApp.gl.glTranslatef(0f, 0f, -50f);
    renderHouse();
  }
  JOApp.gl.glPopMatrix();

  // place the light.  Light will stay in sync with the rest of the scene
  JOApp.setLightPosition(GL.GL_LIGHT1, lightPosition);

  // render some text using texture-mapped font
//  print(30, viewportH- 80, "Left-Right arrows rotate camera", 1);
//  print(30, viewportH-100, "Up-Down arrows move camera forward and back", 1);
//  print(30, viewportH-120, "SPACE toggles dusk/daylight", 1);
//  print(30, viewportH-140, "A W S D keys tilt and pan the camera", 1);
}

void keyPressed() {
  cam.keyPressed(keyEvent);
    
  if (key == ' ') {
    dusk = !dusk;
  }
}

void keyReleased() {
  cam.keyReleased(keyEvent);
}

void keyTyped() {
  cam.keyTyped(keyEvent);
}
